package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminDetailVO;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author hrz
 * @since 2025-08-29
 */
@Service
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final UserClient userClient;
    private final InteractionReplyMapper interactionReplyMapper;
    private final SearchClient searchClient;
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final CategoryCache categoryCache;

    @Override
    public void addQuestion(QuestionFormDTO questionFormDTO) {
        //1.获取用户id
        Long user = UserContext.getUser();
        //2.转换dto为po
        InteractionQuestion question = BeanUtils.copyBean(questionFormDTO, InteractionQuestion.class);
        question.setUserId(user);
        this.save(question);
    }

    @Override
    public void updateQuestion(QuestionFormDTO questionFormDTO, Long id) {
        //1.获取用户id
        Long user = UserContext.getUser();
        //2.更新
        InteractionQuestion question = BeanUtils.copyBean(questionFormDTO, InteractionQuestion.class);
        question.setId(id);
        this.updateById(question);
    }

    @Override
    public PageDTO<QuestionVO> pageQuestion(QuestionPageQuery questionPageQuery) {
        List<QuestionVO> result = new ArrayList<>();
        //-----设置一个缓存系统保存查询过的用户id-----
        HashMap<Long, UserDTO> longUserDTOHashMap = new HashMap<>();
        //1.获取请求参数
        Boolean onlyMe = questionPageQuery.getOnlyMine();
        Long courseId = questionPageQuery.getCourseId();
        Long sectionId = questionPageQuery.getSectionId();
        if (courseId == null && sectionId == null) {
            throw new BizIllegalException("课程id和小节id不能同时为空");
        }
        //用来封装分页查询的变量
        Page<InteractionQuestion> questions = new Page<>();
        //2.判断是不是只查看自己的问题
        if (onlyMe) {
            //只查看自己的问题
            //1.先查询问题 - 用自己的用户id判断
            questions = this.lambdaQuery()
                    .eq(InteractionQuestion::getUserId, UserContext.getUser())
                    .eq(courseId != null, InteractionQuestion::getCourseId, courseId)
                    .eq(sectionId != null, InteractionQuestion::getSectionId, sectionId)
                    .eq(InteractionQuestion::getHidden, false)
                    .page(questionPageQuery.toMpPageDefaultSortByCreateTimeDesc());
            //2.获取了问题列表后,再去查询自己的用户头像和昵称
            UserDTO userDTO = userClient.queryUserById(UserContext.getUser());
            //3.再去获取到最近回答用户的昵称和内容
            List<InteractionQuestion> records = questions.getRecords();
            for (InteractionQuestion record : records) {
                QuestionVO questionVO = BeanUtils.copyBean(record, QuestionVO.class);
                questionVO.setUserName(userDTO.getName());
                questionVO.setUserIcon(userDTO.getIcon());
                Long latestAnswerId = record.getLatestAnswerId(); //最近的回答id
                if (latestAnswerId == null) {
                    //最近无人回答直接跳过封装回答信息的步骤
                    result.add(questionVO);
                    continue;
                }
                InteractionReply interactionReply =
                        interactionReplyMapper.selectById(latestAnswerId);
                Long userId = interactionReply.getUserId();
                String content = interactionReply.getContent();
                if (!interactionReply.getAnonymity()) {
                    //不是匿名才设置昵称
                    UserDTO answerUser = longUserDTOHashMap.get(userId);
                    if (answerUser == null) {
                        //缓存中没有,就去数据库查询
                        answerUser = userClient.queryUserById(userId);
                        //放入缓存
                        longUserDTOHashMap.put(userId, answerUser);
                    }
                    //封装VO的回答者信息
                    questionVO.setLatestReplyUser(answerUser.getName());
                }
                questionVO.setLatestReplyContent(content);
                result.add(questionVO);
            }
        } else {
            //1.查询所有的问题,并按时间排序
            questions = this.lambdaQuery()
                    .eq(courseId != null, InteractionQuestion::getCourseId, courseId)
                    .eq(sectionId != null, InteractionQuestion::getSectionId, sectionId)
                    .eq(InteractionQuestion::getHidden, false)
                    .page(questionPageQuery.toMpPageDefaultSortByCreateTimeDesc());
            List<InteractionQuestion> records = questions.getRecords();
            for (InteractionQuestion record : records) {
                QuestionVO questionVO = BeanUtils.copyBean(record, QuestionVO.class);
                UserDTO userDTO = new UserDTO();
                UserDTO answerUser = new UserDTO();
                //2.获取问题的提问者昵称和头像
                Long userId = record.getUserId();
                //判断缓存中是否有
                if (longUserDTOHashMap.containsKey(userId)) {
                    //有,直接获取
                    userDTO = longUserDTOHashMap.get(userId);
                } else {
                    //没有就去数据库查询并放入缓存
                    userDTO = userClient.queryUserById(userId);
                    longUserDTOHashMap.put(userId, userDTO);
                }
                //封装提问者信息
                questionVO.setUserName(userDTO.getName());
                questionVO.setUserIcon(userDTO.getIcon());
                Long latestAnswerId = record.getLatestAnswerId();
                //3.获取最近回答者的昵称以及回答内容
                if (latestAnswerId != null) {
                    InteractionReply interactionReply =
                            interactionReplyMapper.selectById(latestAnswerId);
                    Long answerUserId = interactionReply.getUserId();
                    String content = interactionReply.getContent();
                    //封装VO的回答者信息
                    if (!interactionReply.getAnonymity()) {
                        //不是匿名就可以获取信息
                        //先去缓存中获取
                        if (longUserDTOHashMap.containsKey(answerUserId)) {
                            //有,直接获取
                            answerUser = longUserDTOHashMap.get(answerUserId);
                        } else {
                            //查询回答者的昵称
                            answerUser = userClient.queryUserById(answerUserId);
                            //放入缓存中
                            longUserDTOHashMap.put(answerUserId, answerUser);
                        }
                        //查询到了之后设置到VO中
                        questionVO.setLatestReplyUser(answerUser.getName());
                    }
                    //设置回答内容
                    questionVO.setLatestReplyContent(content);
                }
                result.add(questionVO);
            } //end for
        } //end else
        return PageDTO.of(questions, result);
    }

    @Override
    public QuestionVO getQuestion(Long id) {
        //1.根据问题的id查询出问题信息
        InteractionQuestion question = this.lambdaQuery()
                .eq(InteractionQuestion::getUserId, id)
                .eq(InteractionQuestion::getId, id)
                .one();
        // 2.数据校验
        if (question == null || question.getHidden()) {
            // 没有数据或者是被隐藏了
            return null;
        }
        //3.再查询出提问者的昵称和头像
        UserDTO userDTO = userClient.queryUserById(UserContext.getUser());
        QuestionVO questionVO = BeanUtils.copyBean(question, QuestionVO.class);
        if (userDTO != null) {
            //如果用户没有注销账户,就设置昵称和头像
            questionVO.setUserName(userDTO.getName());
            questionVO.setUserIcon(userDTO.getIcon());
        }
        return questionVO;
    }

    @Override
    public void deleteQuestion(Long id) {
        //删除问题时需要删除该问题下的所有回答
        //1.先查询问题是否存在
        InteractionQuestion question = this.getById(id);
        if (question == null || !question.getUserId().equals(UserContext.getUser())) {
            throw new BizIllegalException("信息匹配错误!!");
        }
        //2.删除问题
        this.removeById(id);
        //3.删除问题下的所有回答
        interactionReplyMapper.delete(new LambdaQueryWrapper<InteractionReply>()
                .eq(InteractionReply::getQuestionId, id));
    }

    @Override
    public PageDTO<QuestionAdminVO> pageAdminQuestions(QuestionAdminPageQuery query) {
        //1.如果前端传来了课程名称的模糊查询,从ElasticSearch中根据课程名称获取课程id
        String courseName = query.getCourseName();
        List<Long> cIds = null;
        if (courseName != null) {
            cIds = searchClient.queryCoursesIdByName(courseName);
            if (CollUtils.isEmpty(cIds)) {
                return PageDTO.empty(0L, 0L);
            }
        }
        //2.去问题表里面根据信息查询问题信息
        Page<InteractionQuestion> page = this.lambdaQuery()
                .in(cIds != null, InteractionQuestion::getCourseId, cIds)
                .eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())
                .between(query.getBeginTime() != null && query.getEndTime() != null,
                        InteractionQuestion::getCreateTime, query.getBeginTime(), query.getEndTime())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        //3.准备课程id,章节id,用户id的列表
        Set<Long> CourseIds = new HashSet<>();
        Set<Long> UserIds = new HashSet<>();
        Set<Long> ChapterAndSectionIds = new HashSet<>();
        for (InteractionQuestion record : records) {
            UserIds.add(record.getUserId());
            CourseIds.add(record.getCourseId());
            ChapterAndSectionIds.add(record.getChapterId());
            ChapterAndSectionIds.add(record.getSectionId());
        }
        //4.获取提问者名称信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(UserIds);
        Map<Long, UserDTO> userDTOHashMap = new HashMap<>();
        if(CollUtils.isNotEmpty(userDTOS)){
            userDTOHashMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId,
                    c->c));
        }
        //5.获取课程名称信息
        List<CourseSimpleInfoDTO> simpleInfoList =
                courseClient.getSimpleInfoList(CourseIds);
        Map<Long,CourseSimpleInfoDTO> courseMap = new HashMap<>();
        if(CollUtils.isNotEmpty(simpleInfoList)){
            courseMap = simpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId,
                    c->c));
        }
        //6.获取章节信息 - 两个一组
        List<CataSimpleInfoDTO> cataList =
                catalogueClient.batchQueryCatalogue(ChapterAndSectionIds);
        Map<Long,CataSimpleInfoDTO> cataMap = new HashMap<>();
        if(CollUtils.isNotEmpty(cataList)){
            cataMap = cataList.stream().
                    collect(Collectors.toMap(CataSimpleInfoDTO::getId,c->c));
        }
        //7.组装VO
        List<QuestionAdminVO> result = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionAdminVO questionAdminVO = BeanUtils.copyBean(record, QuestionAdminVO.class);
            //8.设置课程名称进去
            questionAdminVO.setCourseName(courseMap.get(record.getCourseId()).getName());
            //9.设置提问者名称
            questionAdminVO.setUserName(userDTOHashMap.get(record.getUserId()).getName());
            //10.设置章节信息
            questionAdminVO.setChapterName(cataMap.get(record.getChapterId()).getName());
            questionAdminVO.setSectionName(cataMap.get(record.getSectionId()).getName());
            //11.设置分类信息
            //12.获取分类信息,先整合课程的三级分类信息 todo 用到了缓存 caffeine
            /*整体思路: 调用cache的getCategoryNames-> 内部getCategoryMap()方法
            * -> categoryClient.getAllOfOneLevel()API
            * -> CategoryController的allOfOneLevel()方法 -> List<Category> list = super.list();
            * -> 获取到了category表中所有行数据并存入缓存 -> 将数据映射到CategoryVO中,并将list返回给上级
            * -> 返回时转换成CategoryBasicDTO数据 -> 将分类id和分类名称映射到map中
            * -> 返回到getCategoryNames方法,根据我们传入的三级分类id组成的集合依次取出分类名称并组合起来
            * */
            CourseSimpleInfoDTO courseInfo = courseMap.get(record.getCourseId());
            String categoryNames = categoryCache.getCategoryNames(List.of(courseInfo.getFirstCateId(),
                    courseInfo.getSecondCateId(),
                    courseInfo.getFirstCateId()));
            questionAdminVO.setCategoryName(categoryNames);
            //13.添加VO到结果集合中
            result.add(questionAdminVO);
        }
        return PageDTO.of(page, result);
    }

    @Override
    public void hiddenQuestion(Long id, Boolean hidden) {
        //1.先查询问题看是否存在
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BizIllegalException("问题不存在");
        }
        //2.更新问题的状态
        question.setHidden(hidden);
        this.updateById(question);
    }

    @Override
    public QuestionAdminDetailVO getQuestionDetail(Long id) {
        //根据前端传来的问题id获取问题详情
        //1.先查询问题详细信息
        InteractionQuestion question = this.lambdaQuery()
                .eq(InteractionQuestion::getId, id)
                .one();
        if(question == null){
            throw new BizIllegalException("问题不存在");
        }
        //2.查询课程信息以及老师信息
        CourseFullInfoDTO courseInfoById =
                courseClient.getCourseInfoById(question.getCourseId(),
                false, true);
        List<Long> teacherIds = courseInfoById.getTeacherIds();
        List<UserDTO> userInfo = userClient.queryUserByIds(teacherIds);
        //3.查询分类名称
        String categoryName = categoryCache.getCategoryNames(courseInfoById.getCategoryIds());
        //4.查询问题的章节信息
        List<CataSimpleInfoDTO> cataInfo =
                catalogueClient.batchQueryCatalogue(List.of(question.getChapterId(),
                        question.getSectionId()));
        Map<Long, String> chapterAndSectionMap =
                cataInfo.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId,
                c -> c.getName()));
        //5.查询用户信息
        UserDTO user = userClient.queryUserById(question.getUserId());
        //6.封装VO
        QuestionAdminDetailVO questionAdminDetail =
                BeanUtils.copyBean(question, QuestionAdminDetailVO.class);
        questionAdminDetail.setCategoryName(categoryName);
        questionAdminDetail.setUserName(user.getName());
        questionAdminDetail.setUserId(user.getId());
        questionAdminDetail.setUserIcon(user.getIcon());
        questionAdminDetail.setCourseName(courseInfoById.getName());
        questionAdminDetail.setChapterName(chapterAndSectionMap.get(question.getChapterId()));
        questionAdminDetail.setSectionName(chapterAndSectionMap.get(question.getSectionId()));
        if(!CollUtils.isEmpty(userInfo)){
            StringJoiner stringJoiner = new StringJoiner(",");
            for (UserDTO userDTO : userInfo) {
                stringJoiner.add(userDTO.getName());
            }
            questionAdminDetail.setTeacherName(stringJoiner.toString());
        }
        return questionAdminDetail;
    }

}
